package com.atguigu.ssyx.product.service.impl;


import cn.hutool.core.bean.BeanUtil;
import com.atguigu.ssyx.common.constant.RedisConst;
import com.atguigu.ssyx.common.exception.SsyxException;
import com.atguigu.ssyx.common.result.ResultCodeEnum;
import com.atguigu.ssyx.model.product.SkuAttrValue;
import com.atguigu.ssyx.model.product.SkuImage;
import com.atguigu.ssyx.model.product.SkuInfo;
import com.atguigu.ssyx.model.product.SkuPoster;
import com.atguigu.ssyx.product.mapper.SkuInfoMapper;
import com.atguigu.ssyx.product.service.ISkuAttrValueService;
import com.atguigu.ssyx.product.service.ISkuImageService;
import com.atguigu.ssyx.product.service.ISkuInfoService;
import com.atguigu.ssyx.product.service.ISkuPosterService;
import com.atguigu.ssyx.vo.product.SkuInfoVo;
import com.atguigu.ssyx.vo.product.SkuStockLockVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

/**
 * <p>
 * sku信息 服务实现类
 * </p>
 *
 * @author author
 * @since 2025-09-13
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class SkuInfoServiceImpl extends ServiceImpl<SkuInfoMapper, SkuInfo> implements ISkuInfoService {

    private final ISkuImageService skuImageService;
    private final ISkuPosterService skuPosterService;
    private final ISkuAttrValueService skuAttrValueService;
    private final SkuInfoMapper skuInfoMapper;

    private final RedisTemplate redisTemplate;

    private final RedissonClient redissonClient;


    @Transactional(rollbackFor = Exception.class)

    @Override
    public void saveSku(SkuInfoVo skuInfoVo) {

        //1.保存Sku的基本信息
        SkuInfo skuInfo = BeanUtil.copyProperties(skuInfoVo, SkuInfo.class);

        this.save(skuInfo);

        //2.保存Sku的平台属性
        //2.1获取Sku的平台属性列表
        List<SkuAttrValue> skuAttrValueList = skuInfoVo.getSkuAttrValueList();

        if (skuAttrValueList != null && skuAttrValueList.size() > 0) {
            int sort = 1;
            for (SkuAttrValue skuAttrValue : skuAttrValueList) {
                skuAttrValue.setSkuId(skuInfo.getId());
                skuAttrValue.setSort(sort++);
            }
        }
        //保存Sku的平台属性
        skuAttrValueService.saveBatch(skuAttrValueList);

        //3.保存Sku的图片

        //3.1获取Sku的图片列表
        List<SkuImage> skuImagesList = skuInfoVo.getSkuImagesList();
        if (skuImagesList != null && skuImagesList.size() > 0) {
            int sort = 1;
            for (SkuImage skuImage : skuImagesList) {
                skuImage.setSkuId(skuInfo.getId());
                skuImage.setSort(sort++);
            }
            //保存Sku的图片
            skuImageService.saveBatch(skuImagesList);
        }

        //4.保存Sku的海报
        List<SkuPoster> skuPosterList = skuInfoVo.getSkuPosterList();
        if (skuPosterList != null && skuPosterList.size() > 0) {
            int sort = 1;
            for (SkuPoster skuPoster : skuPosterList) {
                skuPoster.setSkuId(skuInfo.getId());

                sort++;
            }
            skuPosterService.saveBatch(skuPosterList);

        }


    }

    @Override
    public SkuInfoVo getSkuInfoVo(Long id) {
        //1.查询商品SKU基本信息
        SkuInfo skuInfo = this.getById(id);
        if (skuInfo == null) {
            //抛出异常
            log.error("商品SKU信息不存在");
            throw new SsyxException(ResultCodeEnum.SKUINFONotFound);
        }
        //2.查询商品SKU的图片信息
        List<SkuImage> skuImagesList = skuImageService.getImageListBySkuId(id);
        //3.查询商品SKU的平台属性
        List<SkuAttrValue> skuAttrValueList = skuAttrValueService.getAttrValueListBySkuId(id);
        //4.查询商品SKU的海报信息
        List<SkuPoster> skuPosterList = skuPosterService.getPosterListBySkuId(id);

        //封装数据返回
        SkuInfoVo skuInfoVo = new SkuInfoVo();
        BeanUtils.copyProperties(skuInfo, skuInfoVo);
        skuInfoVo.setSkuImagesList(skuImagesList);
        skuInfoVo.setSkuAttrValueList(skuAttrValueList);
        skuInfoVo.setSkuPosterList(skuPosterList);
        return skuInfoVo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateSku(SkuInfoVo skuInfoVo) {

        //获取Sku的id
        Long id = skuInfoVo.getId();
        log.info("=== baseMapper 是否为 null？ {}", this.baseMapper == null); // 👈 加这行！

        //1.修改sku基本信息
        SkuInfo skuInfo = BeanUtil.copyProperties(skuInfoVo, SkuInfo.class);
        this.updateById(skuInfo);


        //2.先删除之前的海报图片，再重新保存新添加的海报图片
        LambdaQueryWrapper<SkuPoster> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SkuPoster::getSkuId, id);
        //2.1删除之前的海报图片
        skuPosterService.remove(wrapper);

        //2.2保存Sku的海报图片
        List<SkuPoster> skuPosterList = skuInfoVo.getSkuPosterList();
        if (!CollectionUtils.isEmpty(skuPosterList)) {
            for (SkuPoster skuPoster : skuPosterList) {
                //设置Sku的id
                skuPoster.setSkuId(id);
            }
            skuPosterService.saveBatch(skuPosterList);

        }


        //3.先删除之前的图片，再重新保存新添加的图片
        LambdaQueryWrapper<SkuImage> wrapper2 = new LambdaQueryWrapper<>();
        wrapper2.eq(SkuImage::getSkuId, id);
        //3.1删除之前的图片
        skuImageService.remove(wrapper2);

        //3.2保存Sku的图片
        List<SkuImage> skuImagesList = skuInfoVo.getSkuImagesList();
        if (!CollectionUtils.isEmpty(skuImagesList)) {
            int sort = 1;
            for (SkuImage skuImage : skuImagesList) {
                //设置Sku的id
                skuImage.setSkuId(id);
                skuImage.setSort(sort++);

            }
            skuImageService.saveBatch(skuImagesList);

        }

        //4.先删除之前的SKU平台属性，再重新保存新添加的SKU平台属性
        LambdaQueryWrapper<SkuAttrValue> wrapper3 = new LambdaQueryWrapper<>();
        wrapper3.eq(SkuAttrValue::getSkuId, id);
        //4.1删除之前SKU平台属性
        skuAttrValueService.remove(wrapper3);

        //4.2保存Sku的平台属性
        List<SkuAttrValue> skuAttrValueList = skuInfoVo.getSkuAttrValueList();
        if (!CollectionUtils.isEmpty(skuAttrValueList)) {
            int sort = 1;
            for (SkuAttrValue skuAttrValue : skuAttrValueList) {
                //设置Sku的id
                skuAttrValue.setSkuId(id);
                skuAttrValue.setSort(sort++);

            }
            skuAttrValueService.saveBatch(skuAttrValueList);

        }

    }

    //获取新人专享商品
    @Override
    public List<SkuInfo> findNewPersonSkuInfoList() {
        //条件1 ： is_new_person=1
        //条件2 ： publish_status=1
        //条件3 ：显示其中三个
        //获取第一页数据，每页显示三条记录
        Page<SkuInfo> pageParam = new Page<>(1, 3);
        //封装条件
        LambdaQueryWrapper<SkuInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SkuInfo::getIsNewPerson, 1);
        wrapper.eq(SkuInfo::getPublishStatus, 1);
        wrapper.orderByDesc(SkuInfo::getStock);//库存排序
        //调用方法查询
        IPage<SkuInfo> skuInfoPage = baseMapper.selectPage(pageParam, wrapper);
        List<SkuInfo> skuInfoList = skuInfoPage.getRecords();
        return skuInfoList;
    }

    //根据skuId列表得到sku信息列表
    @Override
    public List<SkuInfo> findSkuInfoList(List<Long> skuIdList) {
        List<SkuInfo> skuInfoList = baseMapper.selectBatchIds(skuIdList);
        return skuInfoList;
    }

    //根据关键字匹配sku列表
    @Override
    public List<SkuInfo> findSkuInfoByKeyword(String keyword) {
        List<SkuInfo> skuInfoList = baseMapper.selectList(
                new LambdaQueryWrapper<SkuInfo>().like(SkuInfo::getSkuName, keyword)
        );
        return skuInfoList;
    }


    @Transactional(rollbackFor = {Exception.class})
    @Override
    public Boolean checkAndLock(List<SkuStockLockVo> skuStockLockVoList, String orderNo) {

        //1.判断skuStockLockVoList是否为空
        if (CollectionUtils.isEmpty(skuStockLockVoList)) {
            throw new SsyxException(ResultCodeEnum.DATA_ERROR);
        }
        //2.遍历skuStockLockVoList得到每一个商品，验证库存并锁定库存
        //保证原子性
        skuStockLockVoList.stream().forEach(item -> this.checkLock(item));
        //3.只要有一个商品锁定失败，所有锁定成功的商品都要解锁库存（因为添加购物车的时候，有可能购物车里的库存没有货，如果没有货就重新添加购物车）
        boolean flag = skuStockLockVoList.stream().anyMatch(skuStockLockVo -> !skuStockLockVo.getIsLock());
        if (flag) {
            //所有锁定成功的商品都解锁
            skuStockLockVoList.stream().filter(SkuStockLockVo::getIsLock)
                    .forEach(skuStockLockVo -> {
                        baseMapper.unlockStock(skuStockLockVo.getSkuId(), skuStockLockVo.getSkuNum());
                    });
            //返回失败状态

            return flag;
        }


        //4.如果所有的商品都锁定失败了，redis缓存相关数据，忘了方便后面解锁和减库存使用
        // 如果所有商品都锁定成功的情况下，需要缓存锁定信息到redis。以方便将来解锁库存 或者 减库存
        // 以orderNo作为key，以skuStockLockVoList锁定信息作为value
        this.redisTemplate.opsForValue().set(RedisConst.SROCK_INFO + orderNo, skuStockLockVoList);
        return true;
    }

    //扣减库存成功，更新订单状态
    @Override
    public void minusStock(String orderNo) {
        //从redis获取锁定库存信息
        List<SkuStockLockVo> skuStockLockVoList =
                (List<SkuStockLockVo>)redisTemplate.opsForValue().get(RedisConst.SROCK_INFO + orderNo);
        if(org.springframework.util.CollectionUtils.isEmpty(skuStockLockVoList)) {
            return;
        }
        //遍历集合，得到每个对象，减库存
        skuStockLockVoList.forEach(skuStockLockVo -> {
            baseMapper.minusStock(skuStockLockVo.getSkuId(),skuStockLockVo.getSkuNum());
        });

        //删除redis数据
        redisTemplate.delete(RedisConst.SROCK_INFO + orderNo);
    }


    //2.遍历skuStockLockVoList得到每一个商品，验证库存并锁定库存

    private void checkLock(SkuStockLockVo skuStockLockVo) {
        //公平锁，就是保证客户端获取锁的顺序，跟他们请求获取锁的顺序，是一样的。
        // 公平锁需要排队
        // ，谁先申请获取这把锁，
        // 谁就可以先获取到这把锁，是按照请求的先后顺序来的。
        //sku: 1
        RLock rLock = redissonClient
                .getFairLock(RedisConst.SKUKEY_PREFIX + skuStockLockVo.getSkuId());
        //加锁
        rLock.lock();

        try {
            // 验库存：查询，返回的是满足要求的库存列表
            SkuInfo skuInfo = skuInfoMapper.checkStock(skuStockLockVo.getSkuId(), skuStockLockVo.getSkuNum());
            // 如果没有一个仓库满足要求，这里就验库存失败
            if (null == skuInfo) {
                //如果没有满足条件的商品，设置isLock值为false，返回
                skuStockLockVo.setIsLock(false);
                return;
            }
            // 有满足的，锁库存：更新
            Integer row = skuInfoMapper.lockStock(skuStockLockVo.getSkuId(), skuStockLockVo.getSkuNum());
            if (row == 1) {
                skuStockLockVo.setIsLock(true);
            }
        } finally {
            rLock.unlock();
        }


    }
}